package net.jcip.examples.chapter8;

import java.util.concurrent.Semaphore;

/**
 * Semaphore（信号量）是Java中用于控制同时访问特定资源的线程数或者同时执行特定代码块的线程数的工具类。它在并发编程中起到了很重要的作用，可以用来限制同时访问某一资源的线程数量，或者用来控制同时执行某一代码块的线程数量。
 *
 * 主要特性和用法
 *
 * 	1.	计数器：
 * 	•	Semaphore 内部维护一个计数器，初始化时需要指定许可数（permits），即允许同时访问或执行的线程数量。
 * 	2.	获取和释放许可：
 * 	•	acquire(): 获取一个许可，如果没有可用的许可（计数器为0），则当前线程会被阻塞，直到有其他线程释放许可。
 * 	•	release(): 释放一个许可，增加计数器的值。如果有阻塞的线程在等待许可，则会选择一个线程来获取许可并继续执行。
 * 	3.	应用场景：
 * 	•	资源池控制：例如数据库连接池，限制同时可用的连接数量。
 * 	•	并发任务控制：限制同时执行的任务数量，保护共享资源避免过多线程同时访问。
 * 	•	控制流量：限制同时进行的网络连接或文件访问数量，防止过载。
 */
public class SemaphoreExample {
    // 初始化一个Semaphore，限制最多同时有3个线程访问共享资源
    private static Semaphore semaphore = new Semaphore(3);

    //公平的获取顺序
    //private static Semaphore semaphore = new Semaphore(3,true);

    public static void main(String[] args) {
        // 创建10个线程尝试访问共享资源
        for (int i = 1; i <= 10; i++) {
            Thread thread = new Thread(new WorkerThread(i));
            thread.start();
        }
    }

    static class WorkerThread implements Runnable {
        private final int threadId;

        public WorkerThread(int id) {
            this.threadId = id;
        }

        @Override
        public void run() {
            try {
                System.out.println("Thread " + threadId + " is trying to acquire a permit.");
                semaphore.acquire(); // 获取一个许可
                System.out.println("Thread " + threadId + " has acquired a permit.");

                // Simulate some work
                Thread.sleep(2000);

                System.out.println("Thread " + threadId + " is releasing a permit.");
                semaphore.release(); // 释放一个许可
                System.out.println("Thread " + threadId + " has released a permit.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
